package org.wooxes.server;

import java.io.*;
import java.net.*;
import java.sql.*;
import java.util.*;
import java.util.zip.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.ServletException;
import org.apache.commons.fileupload.*;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 *
 * @author woox
 */
public class UploadServlet extends HttpServlet{
    public void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // S'inicialitza la sortida per poder mostrar resposta
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        
        // Mirem si es multipart
        if(!ServletFileUpload.isMultipartContent(request)){
            return;
        }
        
        // Ara obtindrem valors de configuracio
        ConnexioSQL connexio = new ConnexioSQL();
        Connection conn = connexio.getConnection();
        ConfiguracioServidor config = new ConfiguracioServidor(conn);
        
        // Comencem el servlet
        FileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        upload.setFileSizeMax(config.getMaxFileSize());

        List items = null;
        try {
            items = upload.parseRequest(request);
        }
        catch(FileUploadException e){
            System.out.println(e);
            out.println(e.toString());
            return;
        }

        // Aqui es processen els diferents camps del formulari.
        int id=0;
        String alumne = "";
        for (Iterator i = items.iterator(); i.hasNext();) {
            FileItem item = (FileItem) i.next();
            
            if(item.isFormField()){
                if(item.getFieldName().equals("id")){
                    // Aquí obtenim l'identificador de la practica (ID)
                    id = Integer.parseInt(item.getString());
                }
                else if(item.getFieldName().equals("username")){
                    // Aquí obtenim el nom de l'usuari que envia l'arxiu
                    alumne = item.getString("UTF-8");
                }
                continue;
            }
            
            //Es comprova l'extensio del fitxer, ha de ser un .zip
            String fileName = obtenirNomArxiu(item.getName());      // Obtenim nom d'arxiu
            if(!fileName.substring(fileName.lastIndexOf(".")+1).equals("zip")){
                out.println("Error: Ha de ser un arxiu .zip");
                return;
            }
            String ruta = config.getUploadDir();                    // Obtenim directori desti

            // Creació de la ruta (directori) destí
            // /id_activitat/
            ruta = ruta + id + File.separator;
            File uploaddir = new File(ruta);

            // Es crea directori per directori, per tenir més control
            if(!crearDirectori(uploaddir)){
                out.println("Error: No es pot crear el directori desti: " + uploaddir.toString());
                return;
            }

            ruta = ruta + "entregues" + File.separator;
            uploaddir = new File(ruta);

            // Creació del directori entregues
            // /id_activitat/entregues/
            File uploadedFile = new File(ruta + fileName);
            if(!crearDirectori(uploaddir)){
                out.println("Error: No es pot crear el directori desti: " + uploaddir.toString());
                return;
            }

            if(uploadedFile.exists() && uploadedFile.isFile()){
                out.println("Error: Arxiu ja existent");
                return;
            }
            try{
                item.write(uploadedFile);                           // S'escriu l'arxiu en el disc dur
            }
            catch (Exception e) {
                out.println(e.toString());
                return;
            }
            
            // Ara pasem a descomprimir l'arxiu zip, dins una carpeta
            
            // Creem nou directori, on descomprimir, amb el mateix nom que l'arxiu original, pero sense la extensio
            ruta = uploadedFile.toString();
            ruta = ruta.substring(0,ruta.lastIndexOf("."));
            // S'afegeix barra a la ruta del directori
            ruta = ruta + File.separator;

            File newdir = new File (ruta);
            if(!crearDirectori(newdir)){
                // Es crea el directori on es descomprimirà l'arxiu
                out.println("Error: No es pot crear el directori: "+ newdir.toString());
                return;
            }
            
            // Descomprimim arxiu
            if(!descomprimirArxiu(uploadedFile,ruta)){
                out.println("Error: No s'ha pogut descomprimir arxiu .zip");
                eliminarArxius(uploadedFile, ruta);
                return;
                // aqui s'haura de esborrar l'entrada de la bd i les carpetes-arxius creats
            }
            
            // Grabar entrega a la bd;
            if(actualitzarBD(conn, id, alumne, fileName)==0){
                // Si no s'ha pogut insertar la nova entrega, es borra arxiu
                out.println("Error: No s'ha pogut actualitzar la BD");
                eliminarArxius(uploadedFile, ruta);
                return;
            }
        }
        out.println("ok");
        out.close();
    }
    
    private int actualitzarBD(Connection conn, int id, String alumne, String arxiu){
        try{
            Statement statement = conn.createStatement();
            // CAMBIAR LA DATA I LA HORA!!!
            
            Calendar c = Calendar.getInstance();
            Date d = c.getTime();
            SimpleDateFormat format1 = new SimpleDateFormat("yyyyMMdd");
            String data = format1.format(d);
            SimpleDateFormat format2 = new SimpleDateFormat("HH:mm:ss");
            String hora = format2.format(d);
            
            int i=statement.executeUpdate(
                    "INSERT INTO entrega (idactivitat, alumne, arxiu, data, hora) values"+
                    "("+id+", '"+alumne+"', '"+arxiu+"', '"+data+"', '"+hora+"')");
            return i;
        }
        catch(Exception e){
            System.out.println(e);
            return 0;
        }
    }
    
    private void eliminarArxius(File arxiu, String directori){
            if(!arxiu.delete()){
                System.out.println("No s'ha pogut borrar l'arxiu: "+arxiu.toString());
            }

            if(!DeleteFile.deleteDirectory(directori)){
                System.out.println("No s'ha pogut borrar el directori: "+directori);
            }
    }
    private boolean crearDirectori(File directori){
        boolean bool = directori.exists();
        if(bool){
            // Comprovem si el que existeix es un directori
            bool = directori.isDirectory();
        }
        if (bool != true){
            bool=directori.mkdir();
        }
        System.out.println("Creant directori: " + directori.toString() + " -> " + bool);
        return bool;
    }
    
    private String obtenirNomArxiu(String fileName){
        int slash = fileName.lastIndexOf("/");      // Si es tracta d'un usuari Linux
        if (slash == -1) {
            slash = fileName.lastIndexOf("\\");     // Si es tracta d'un usuari Windows
        }
        if (slash != -1) {
            fileName = fileName.substring(slash +1 );
        }
        return fileName;
    }

    private boolean descomprimirArxiu(File file, String ruta){
        System.out.println("Descomprimint: " + file.toString() + " | Al directori: " + ruta);
        
        // Un buffer de 2048 B
        int tamanyBuffer = 2048;
        byte buffer[] = new byte[tamanyBuffer];

        try{
            ZipFile arxiu = new ZipFile(file);
            Enumeration e = arxiu.entries();
            ZipEntry entry;

            while (e.hasMoreElements()){
                entry = (ZipEntry) e.nextElement();
                
                // Si es tracta d'una carpeta, es crea
                if(entry.isDirectory()){
                    File directori = new File(ruta + entry.getName());
                    crearDirectori(directori);
                    continue;
                }

                // Comencem lectura si es tracta d'un arxiu
                InputStream is = arxiu.getInputStream(entry);                           // Input Stream
                FileOutputStream fos = new FileOutputStream(ruta + entry.getName());    // Output Stream

                // Buffered ja que aixi no ha de escriure a disc per cada write
                BufferedOutputStream bos = new BufferedOutputStream(fos, tamanyBuffer); // Output Stream a utilitzar

                int llegits=0;
                while((llegits = is.read(buffer)) != -1){
                    fos.write(buffer,0,llegits);
                }

                bos.flush();
                bos.close();
                is.close();
            }
            return true;
        }
        catch(Exception e){
            System.out.println(e);
            return false;
        }
        
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /** Handles the HTTP <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        processRequest(request, response);
    }
    
    /** Returns a short description of the servlet.
     */
    public String getServletInfo() {
        return "Short description";
    }
    // </editor-fold>
}
